//
// This code is to be used for evaluation of the CS2J tool ONLY.
//
// This file was translated from C# to Java by CS2J (http://www.cs2j.com).
//
// For more information about CS2J please contact info@twigletsoftware.com
//
// Translated by CS2J (http://www.cs2j.com): 2013/1/12 14:27:24
//

package ms.sudoku.technique;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import ms.sudoku.PuzzleState;
import ms.sudoku.util.IntSet;

import common.Sudokus;

public final class XwingTechnique extends EliminationTechnique {
	public XwingTechnique() {
	}

	public long getDifficultyLevel() {
		return 11;
	}

	public boolean execute(PuzzleState state, boolean exitEarlyWhenSoleFound, IntSet[][] possibleNumbers,
			AtomicInteger numberOfChanges, AtomicBoolean exitedEarly) {
		numberOfChanges.set(0);
		exitedEarly.set(false);

		int gridSize = state.getGridSize();

		for (int row = 0; row < gridSize; row++) {
			int count = 0;
			// used to find the two first-row members of the x-wing
			int[] foundColumns = new int[2];
			for (int n = 0; n < gridSize; n++) {
				for (int column = 0; column < gridSize; column++) {
					// used to store the two first-row members of the x-wing
					int num = state.get(row, column);
					if (possibleNumbers[row][column].contains(n) || (false == Sudokus.isEmpty(num) && num == n)) {
						count++;
						if (count <= foundColumns.length)
							foundColumns[count - 1] = column;
						else
							break;
					}
				}

				if (count == 2) {
					for (int subRow = row + 1; subRow < gridSize; subRow++) {
						boolean validXwingFound = true;
						for (int subColumn = 0; subColumn < gridSize && validXwingFound; subColumn++) {
							int num = state.get(subRow, subColumn);
							boolean isMatchingColumn = (subColumn == foundColumns[0] || subColumn == foundColumns[1]);
							boolean hasPossibleNumber = possibleNumbers[subRow][subColumn].contains(n)
									|| (false == Sudokus.isEmpty(num) && num == n);
							if ((hasPossibleNumber && !isMatchingColumn) || (!hasPossibleNumber && isMatchingColumn))
								validXwingFound = false;

						}
						if (validXwingFound) {
							for (int elimRow = 0; elimRow < gridSize; elimRow++) {
								if (elimRow != row && elimRow != subRow) {
									for (int locationNum = 0; locationNum < 2; locationNum++) {
										if (possibleNumbers[elimRow][foundColumns[locationNum]].contains(n)) {
											possibleNumbers[elimRow][foundColumns[locationNum]].remove(n);
											numberOfChanges.incrementAndGet();
											if (exitEarlyWhenSoleFound
													&& possibleNumbers[elimRow][foundColumns[locationNum]].size() == 1) {
												exitedEarly.set(true);
												return false;
											}
										}
									}
								}
							}
							break;
						}
					}
				}
			}
		}
		return numberOfChanges.get() != 0;
	}

}
